﻿///<copyright>
/// Copyright © 2009 Stephen Styrchak. All Rights Reserved.
///</copyright>
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Ferpect.ComponentModel.Menus
{
    public class MenuInputHandler : ControllerComponent
    {
        private IInputService inputService;
        private InputEventArgs[] inputEventArgs;
        private bool activating;

        public event EventHandler<InputEventArgs> Back;
        public event EventHandler<InputEventArgs> Pause;
        public event EventHandler<InputEventArgs> Accept;
        public event EventHandler<InputEventArgs> Cancel;
        public event EventHandler<InputEventArgs> Down;
        public event EventHandler<InputEventArgs> Up;
        public event EventHandler<InputEventArgs> Right;
        public event EventHandler<InputEventArgs> Left;
        public event EventHandler<InputEventArgs> PageDown;
        public event EventHandler<InputEventArgs> PageUp;

        protected override void LoadContent()
        {
            base.LoadContent();
            this.inputService = (IInputService)this.GetService(typeof(IInputService));
            this.inputEventArgs = new InputEventArgs[4];
            this.inputEventArgs[(int)PlayerIndex.One] = InputEventArgs.PlayerOne;
            this.inputEventArgs[(int)PlayerIndex.Two] = InputEventArgs.PlayerTwo;
            this.inputEventArgs[(int)PlayerIndex.Three] = InputEventArgs.PlayerThree;
            this.inputEventArgs[(int)PlayerIndex.Four] = InputEventArgs.PlayerFour;
        }

        public override void Update(Microsoft.Xna.Framework.GameTime gameTime)
        {
            if (this.inputService != null)
            {
                if (this.activating)
                {
                    this.activating = false;
                }
                else
                {
                    for (int i = 0; i < 4; ++i)
                    {
                        this.RaiseInputEvents(i);
                    }
                    this.RaiseKeyPressEvents();
                }
            }
        }

        public override bool Enabled
        {
            set
            {
                this.activating = value;
                base.Enabled = value;
            }
        }

        /// <summary>
        /// This method raises the input events in priority order.
        /// </summary>
        /// <param name="index">The index of the input state to use (inputStates array).</param>
        private void RaiseInputEvents(int index)
        {
            InputState state = this.inputService.GetInputState((PlayerIndex)index);

            if (state.IsConnected)
            {
                this.RaisePause(state);
                this.RaiseBack(state);
                this.RaiseAccept(state);
                this.RaiseCancel(state);
                this.RaiseDown(state);
                this.RaiseUp(state);
                this.RaiseRight(state);
                this.RaiseLeft(state);
                this.RaisePageDown(state);
                this.RaisePageUp(state);
            }
        }

        private void RaiseKeyPressEvents()
        {
            this.RaiseKeyPressEvent(this.Accept, Keys.Enter);
            this.RaiseKeyPressEvent(this.Cancel, Keys.Escape);
            this.RaiseKeyPressEvent(this.Up, Keys.Up);
            this.RaiseKeyPressEvent(this.Down, Keys.Down);
            this.RaiseKeyPressEvent(this.Left, Keys.Left);
            this.RaiseKeyPressEvent(this.Right, Keys.Right);
            this.RaiseKeyPressEvent(this.PageUp, Keys.PageUp);
            this.RaiseKeyPressEvent(this.PageDown, Keys.PageDown);
            this.RaiseKeyPressEvent(this.Back, Keys.Back);
            this.RaiseKeyPressEvent(this.Pause, Keys.Pause);
        }

        private void RaiseKeyPressEvent(EventHandler<InputEventArgs> keyPressEvent, Keys keys)
        {
            if (keyPressEvent != null && this.inputService.Keyboard.IsNewKeyPress(keys))
            {
                keyPressEvent(this, InputEventArgs.Keyboard);
            }
        }

        protected virtual void RaiseAccept(InputState state)
        {
            if (this.Accept != null)
            {
                if (state.IsNewButtonPress(Buttons.A))
                {
                    this.Accept(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaiseCancel(InputState state)
        {
            if (this.Cancel != null)
            {
                if (state.IsNewButtonPress(Buttons.B))
                {
                    this.Cancel(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaiseUp(InputState state)
        {
            if (this.Up != null)
            {
                if (state.IsNewButtonPress(Buttons.DPadUp) || state.IsNewButtonPress(Buttons.LeftThumbstickUp))
                {
                    this.Up(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaiseDown(InputState state)
        {
            if (this.Down != null)
            {
                if (state.IsNewButtonPress(Buttons.DPadDown) || state.IsNewButtonPress(Buttons.LeftThumbstickDown))
                {
                    this.Down(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaisePageUp(InputState state)
        {
            if (this.PageUp != null)
            {
                if (state.IsNewButtonPress(Buttons.LeftTrigger))
                {
                    this.PageUp(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaisePageDown(InputState state)
        {
            if (this.PageDown != null)
            {
                if (state.IsNewButtonPress(Buttons.RightTrigger))
                {
                    this.PageDown(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaiseRight(InputState state)
        {
            if (this.Right != null)
            {
                if (state.IsNewButtonPress(Buttons.DPadRight) || state.IsNewButtonPress(Buttons.LeftThumbstickRight))
                {
                    this.Right(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaiseLeft(InputState state)
        {
            if (this.Left != null)
            {
                if (state.IsNewButtonPress(Buttons.DPadLeft) || state.IsNewButtonPress(Buttons.LeftThumbstickLeft))
                {
                    this.Left(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaiseBack(InputState state)
        {
            if (this.Back != null)
            {
                if (state.IsNewButtonPress(Buttons.Back))
                {
                    this.Back(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }

        protected virtual void RaisePause(InputState state)
        {
            if (this.Pause != null)
            {
                if (state.IsNewButtonPress(Buttons.Start))
                {
                    this.Pause(this, this.inputEventArgs[(int)state.PlayerIndex]);
                }
            }
        }
    }
}
